package reflection;

import java.lang.reflect.Method;

/**
 * 通过反射访问方法
 */
public class ReflectAccessMethod {
    public static void main(String[] args) throws Exception {

        /*
            1.根据方法名和参数列表获取Methods方法对象
              Method m = clazz.getDeclaredmethod(方法名, XX.class);
            2.获取对象 Object o = clazz.new Instance();
            3.爆破 m.setAccessible(true)
            4.访问 Object returnValue = m.invoke(o,实参列表)

            tips:如果是静态方法，invoke()的参数o，可以写成null
         */
        //1. 得到Boss 类对应的Class对象
        Class<?> bossCls = Class.forName("reflection.Boss");
        //2. 创建对象
        Object o = bossCls.newInstance();
        //3. 调用public 的 hi 方法
        //Method hi = bossCls.getMethod("hi", String.class);//OK
        //3.1 得到 hi 方法对象
        Method hi = bossCls.getDeclaredMethod("hi", String.class);//OK
        //3.2 调用
        hi.invoke(o, "lmy");

        //4. 调用private static 方法
        //4.1 得到 say 方法对象
        Method say = bossCls.getDeclaredMethod("say", int.class, String.class, char.class);
        say.setAccessible(true);
        System.out.println(say.invoke(o, 100, "张三", '男'));
        //4.2 因为 say 方法是private, 所以需要暴破，原理和前面讲的构造器和属性一样
        //4.3 因为 say 方法是static的，还可以这样调用 ，可以传入null
        System.out.println(say.invoke(null, 200, "李四", '女'));

        //5. 在反射中，如果方法有返回值，统一返回Object, 但是他运行类型和方法定义的返回类型一致
        Object reVal = say.invoke(null, 300, "王五", '男');
        System.out.println("reVal 的运行类型=" + reVal.getClass());//String

        Method m1 = bossCls.getDeclaredMethod("m1");
        Object reVal2 = m1.invoke(o);
        System.out.println("reVal2 的运行类型=" + reVal2.getClass());//Monster
    }
}
